using System;
using System.Collections;
using System.Collections.Generic;
using System.Html;
using System.Runtime.CompilerServices;
using Awaiter;
using Nsb;
using Nsb.Classes;
using ThemeChain;
using Yoshi.Classes;
using jQueryApi;

namespace PhotoUpload.Classes
{
    [IgnoreNamespace]
    public class PhotoUploadViewer : Actor
    {
        private static PhotoUploadViewer _instance;
        private readonly PhotoUploadOptions _opts;
        private jQueryObject _topBar;

        public PhotoUploadViewer(PhotoUploadOptions opts)
        {
            if (_instance != null)
                _instance.CloseEv(null);
            _instance = this;
            _opts = opts;
            GlassOff();
            Element = jQuery.FromHtml("<div id='PhotoUploadViewer' class='AboveHider'/>")
                ;
        }

        // ReSharper disable SuspiciousTypeConversion.Global
        [PreserveName, PreserveCase]
        public static void Ev(jQueryEvent e, Dictionary opts)
        {
            jQueryObject el = (jQueryObject) opts["Element"] ?? jQuery.FromElement(Document.Body);
            new PhotoUploadViewer((PhotoUploadOptions) (object) opts).BuildTo(el);
        }

        // ReSharper restore SuspiciousTypeConversion.Global

        public void BuildTo(jQueryObject el)
        {
            if (Element != null)
                Element.Empty();
            new Await()
                .AddAw(GetImgDbAw)
                .HandleDx(Exceptions.BlobLoadError, delegate(Await aw) { aw.Result = new Dictionary(); })
                .AddAw(BuildAw, el)
                .Commit();
        }

        private void BuildAw(Await awp, jQueryObject el)
        {
            Element.AppendTo(el).Plugin<Jewl>().Position(new Dictionary("my", "center top", "at", "center bottom", "of", Window.Self, "collision", "fit fit", "offset", "0 -300"));
            Element.CSS(new Dictionary("bottom", 0 - Document.Body.ScrollTop));

            _topBar = jQuery.FromHtml("<div class='TopBar'/>")
                .AppendTo(Element)
                ;

            ReDraggerEv();

            jQuery.Document
                .Bind("scroll.puv", delegate
                                    {
                                        Element.CSS(new Dictionary("bottom", 0 - Document.Body.ScrollTop));
                                        ReDraggerEv();
                                    })
                .Bind("resize.puv", ReDraggerEv)
                ;

            jQuery.FromHtml("<button class='UploadBtn'/>")
                .AppendTo(_topBar)
                .Html("add new image")
                .Click(AskUploadEv)
                ;

            jQuery.FromHtml("<div class='CancelBtn'/>")
                .AppendTo(_topBar)
                .Html("<img src='" + Uri.Img("Common/close20.png") + "' width='20' height='20' border='0'>")
                .Click(CloseEv)
                ;

            jQuery.FromHtml("<span class='Info'/>")
                .AppendTo(_topBar)
                .Html("drag these images onto page above or use add button to add more images")
                ;

            jQueryObject content = jQuery.FromHtml("<div class='Content'/>")
                .AppendTo(Element)
                ;

            foreach (KeyValuePair<string, ImageItem> p in (Dictionary<string, ImageItem>) awp.Result)
            {
                string url = p.Value.Thumb ?? p.Value.Source;
                jQuery.FromHtml("<img class='PhotoImage'/>")
                    .PrependTo(
                        jQuery.FromHtml("<div class='PhotoItem'/>")
                            .AppendTo(content)
                            .Append(
                                jQuery.FromHtml("<div class='PhotoDelete'/>")
                                    .Html("\u2716" /*thick x*/)
                                    .Attribute("title", "delete this image from image database")
                                    .Click(DelEvHandler(p.Key))
                            )
                            .Append(
                                jQuery.FromHtml("<div class='PhotoInfo'/>")
                                    .Html(String.Format("{0}", p.Value.Width + " x " + p.Value.Height))
                            )
                    )
                    .Attribute("src", url)
                    .Attribute("width", (Math.Min(p.Value.Width, 100)) + "px")
                    ;
            }
            awp.Done();
        }

        [AlternateSignature]
        private extern void ReDraggerEv();

        private void ReDraggerEv(jQueryEvent e)
        {
            int ofst = jQuery.Window.GetHeight() - (_topBar.GetOuterHeight() + Number.ParseInt(Element.GetCSS("border-top-width")) + 10 - Document.Body.ScrollTop);

            //Inform.Debug(String.Format("[0,0,{0},{1},{2}]", jQuery.Window.GetWidth(), jQuery.Window.GetHeight(), ofst));

            Element.Plugin<Jewl>().Draggable(
                new Dictionary(
                    "handle", _topBar,
                    "containment", Script.Literal("[0,0,{0},{1}]", jQuery.Window.GetWidth(), ofst),
                    "axis", "y",
                    "scroll", false,
                    "drag", (jQueryEventHandler) delegate { Element.CSS(new Dictionary("bottom", 0 - Document.Body.ScrollTop)); }
                    )
                );
        }

        private jQueryEventHandler DelEvHandler(string url)
        {
            return delegate(jQueryEvent e)
                   {
                       new Await()
                           .AddAw(new Ask().OkCancelAw, new Dictionary("Msg", ThemeYoshi.ForSure))
                           .AddAw(RequireResultAw, true)
                           .AddDx(delegate
                                  {
                                      DeleteImageAw(Await.AsyncAw, url);
                                      jQuery.FromElement(e.Target).Closest(".PhotoItem").Remove();
                                  })
                           .Commit();
                   };
        }

        public void DeleteImageAw(Await awp, string url)
        {
            FileManager.UpdateFileAw(awp, ThemeYoshi.ImagesPartitionKey, ThemeYoshi.ImagesRowKey,
                                     delegate(object imagesD)
                                     {
                                         Dictionary<string, ImageItem> imgs = (Dictionary) imagesD;
                                         ImageItem ii = imgs[url];
                                         if (ii != null)
                                         {
                                             if (ii.Path != null)
                                                 ImageManager.DeleteImageAw(Await.AsyncAw, ii.Path);
                                             if (ii.Thumb != null)
                                                 ImageManager.DeleteImageAw(Await.AsyncAw, ii.Thumb);
                                             imgs.Remove(url);
                                         }
                                     })
                ;
        }

        //private jQueryObject CanvasImg(string src)
        //{
        //    //Script.Literal("debugger");
        //    jQueryObject cv = jQuery.FromHtml("<canvas/>");
        //    object ctx = Script.Literal("{0}.getContext('2d')", cv[0]);
        //    Element img = (Element)Script.Literal("new Image()");
        //    Action dl = delegate
        //                {
        //                    //Script.Literal("debugger");
        //                    jQueryObject el = jQuery.FromElement(img);
        //                    Script.Literal("{0}.drawImage({1}, 0, 0, 100, 100)", ctx, img);
        //                    cv.InsertBefore(el);
        //                    el.Remove();
        //                };
        //    Script.Literal("{0}.onload = {1}", img, dl);
        //    return jQuery.FromElement(img);
        //}

        private void AskUploadEv(jQueryEvent e)
        {
            string fileName = "ms." + Formulas.NewId;
            new Await()
                .AddAw(new Ask().FileUploadAw,
                       new Dictionary(
                           "Msg", "Upload an image",
                           "path", _opts.Path,
                           "filename", fileName,
                           "password", (string)Storage.GetLocal(ThemeYoshi.CuratePasswordKey),
                           "action", AfterUploadCx(_opts.Path)
                           ))
                .Commit();
        }

        private static Action AfterUploadCx(string path)
        {
            Storage.SetSession("xPath", path);
            return delegate
                   {
                       string fullName = Uri.Join(ThemeBase.AppUri, ((Dictionary<string, string>)Storage.GetSession(ThemeBase.RedirectDataKey))["fullName"]);
                       new Await()
                           .AddAw(ImageManager.UpdateImageDataAw, fullName)
                           .Sleep(500)
                           .LoadAndDo(Uri.Scripts("Scripts/PhotoUpload.js"), "PhotoUploadViewer.Ev", new Dictionary("Path", (string)Storage.GetSession("xPath")))
                           .AddDx(delegate { Storage.RemoveSession("xPath");})
                           .Commit();
                   };
        }

        public void CloseEv(jQueryEvent e)
        {
            _instance = null;
            CancelEvent(e);
            Element.Remove();
            jQuery.Document.Unbind(".puv");
        }

        private void GetImgDbAw(Await awp)
        {
            new Await()
                .AddAw(FileBlobBase.RetrieveBlobAw, ThemeYoshi.ImagesPartitionKey, ThemeYoshi.ImagesRowKey)
                .Commit(awp);
        }

        [PreserveName, PreserveCase]
        public static void UpdateDirImagesEv(jQueryEvent e, Dictionary opts)
        {
            // ReSharper disable SuspiciousTypeConversion.Global
            PhotoUploadOptions puo = (PhotoUploadOptions) (object) opts;
            // ReSharper restore SuspiciousTypeConversion.Global
            new Await()
                .AddAw(FileBlobBase.GetDirAw, puo.Path, true)
                .AddDx(delegate(Await aw) { puo.DirMap = (DirMap) aw.Result; })
                .AddDl(
                    delegate(Await aw)
                    {
                        Await awx = new Await();
                        List<string> files = puo.DirMap.files;
                        for (int i = 0; i < files.Count; i++)
                        {
                            if (!((RegularExpression) Script.Literal(@"/^(@|tn\.|ms\.)/i")).Test(files[i]))
                                awx.AddAw(ImageManager.UpdateImageDataAw, Uri.Join(ThemeBase.AppUri, puo.Path, files[i]));
                        }
                        awx.Commit(aw);
                    })
                .AddAw(FileBlobBase.RetrieveBlobAw, ThemeYoshi.ImagesPartitionKey, ThemeYoshi.ImagesRowKey)
                .AddDl(
                    delegate(Await aw)
                    {
                        Dictionary<string, ImageItem> imgs = (Dictionary) aw.Result;
                        Await awx = new Await();
                        foreach (KeyValuePair<string, ImageItem> p in imgs)
                        {
                            awx.AddAw(ImageManager.UpdateImageDataAw, p.Value.Source);
                        }
                        awx.Commit(aw);
                    })
                .Commit();
        }
    }

    public sealed class PhotoUploadOptions
    {
        [PreserveName, PreserveCase] public DirMap DirMap;
        [PreserveName, PreserveCase] public string Path;
    }
}